use crate::noted;
use std::borrow::Cow::Owned;
use std::borrow::{Borrow, Cow};
use std::ops::Deref;

//##################################################################################################//
/// cow 类型 写时拷贝
/// 如果对变量的大部分场景是读多写少，那么建议使用cow管理变量，避免频繁的复制
/// 例子：
/// 1. 如果需要读取一个字符串的信息但是不想再函数间反复拷贝
/// 2. 大部分只是读取数据，但是存在少数情况需要拷贝，希望可以延迟决定

// 此案例：如果对入参&str进行去除空格校验不可避免要进行String拷贝，
// 但是如果能确定是否存在是否存在空格的情况下在进行操作流程控制，就可以避免多余的拷贝
fn remove_spaces(input_str: &str) -> Cow<'_, str> {
    if input_str.contains(" ") {
        let mut tmp = String::with_capacity(input_str.len());
        for x in input_str.chars() {
            if x != ' ' {
                tmp.push(x);
            }
        }
        return Cow::Owned(tmp);
    }
    Cow::Borrowed(input_str)
}

/// Cow要求变量类型默认实现ToOwned
/// 但是rust已经默认给所有的T实现了ToOwned，但是要求T:Clone,且可以满足Borrow转换
/// 因此Cow常用于地址，文件解析，字符串处理等功能
#[test]
fn borrow_test() {
    let cow = Cow::from("asd"); // borrow &str
    let cow_string = Cow::from("asd".to_string()); // owned String
    fn print_test(input: &str) {}
}

//##################################################################################################//
/// Deref trait作为一个可以提供隐式引用转换的特性，可以解决复杂的类型强转问题
/// 1. 提供类似对于指针类型的解引用操作，包括包装类型处理等
/// 2. 在编译器层面提供了自动转换优化
struct DerefModel {
    msg: String,
}

impl DerefModel {
    pub fn new(msg: String) -> Self {
        Self { msg }
    }
}

impl Deref for DerefModel {
    type Target = String;

    fn deref(&self) -> &Self::Target {
        &self.msg
    }
}

#[test]
fn deref_test1() {
    let model = DerefModel::new("msg".to_string());
    println!("{}", *model); // deref实现保证*model获取的是String的内容
    println!("{}", model.len()); // deref实现保证model.len()获取的是String的方法
    println!("{}", model.msg); // 等同于直接获取msg

    ///deref用途注意
    ///1. 一般用于暴露内部的对象，当外部包装是&时，解引用需要两层
    ///2. 自动获得内部对象的方法的属性
    noted!();
}

//##################################################################################################//
/// AsRef trait
/// rust不存在继承关系，如果需要在函数层面体现继承的效果可以使用AsRef trait
/// 通常使用AsRef实现面向父类编程的效果
struct Model {
    base: String,
}

struct AsRefModelExt {
    model: Model,
    extend: String,
}

struct AsRefModelOver {
    model: Model,
    over: String,
}

impl AsRef<Model> for AsRefModelExt {
    fn as_ref(&self) -> &Model {
        &self.model
    }
}

impl AsRef<Model> for AsRefModelOver {
    fn as_ref(&self) -> &Model {
        &self.model
    }
}

fn as_ref_func(model: impl AsRef<Model>) {
    println!("model info:{}", model.as_ref().base);
}

#[test]
fn as_ref_test() {
    as_ref_func(AsRefModelOver {
        model: Model {
            base: "ok".to_string(),
        },
        over: "over".to_string(),
    });
}

//##################################################################################################//
/// Borrow trait
/// borrow如其名希望当前类可以同时拥有和提供借出内部变量的效果
/// 一般用于提供内部变量的借用
struct BorrowModel {
    msg: String,
}

impl Borrow<String> for BorrowModel {
    fn borrow(&self) -> &String {
        &self.msg
    }
}
//##################################################################################################//

#[test]
fn summarize_test() {
    /// Deref使用关联类型 ,限制同一个类型只有一个实现，要求解引用效果有且唯一，减少编译器对其复杂的自动判断
    /// AsRef使用泛型,  常用于子父级关系的在函数入参的体现
    /// Borrow使用泛型, 常用于借出内部变量的特点
    /// Cow是对Borrow的扩展，要求变量实现Borrow同时满足对变量的所有权获取的实现

    noted!();
}
